import { GAP, HOVER_EHGIT, HOVER_WIDTH } from "./config";
import { SvgBase } from "./svgBase";
import { IData, IDataObj } from "./type";
import { $, UUID } from "./utils";

export class Data {
    private _dataObj: IDataObj = {};
    private _firstId: string = ''; // 起点ID
    private _svgBase: SvgBase;
    private _hoverId: string = ''; // 当前悬停的ID

    constructor(svgBase: SvgBase) {
        this._svgBase = svgBase;
    }

    // 添加/更新节点
    save(d: IData) {
        if (!this._firstId) {
            this._firstId = d.id;
        }
        this._dataObj[d.id] = d;
        this._svgBase.gRect(d.x, d.y, d.w, d.h, {
            fill: '#409EFF',
            id: d.id,
        });
        this._svgBase.gText(d.x + d.w / 2, d.y + d.h / 2, d.id, {
            id: d.id + '_text',
        });
        if (d.parentId) {
            const parentEle = this._dataObj[d.parentId];
            if (parentEle) {
                this._svgBase.gLine(parentEle.x + parentEle.w, parentEle.y + parentEle.h / 2, d.x, d.y + d.h / 2, {
                    stroke: '#0000FF', // 蓝色横线
                    strokeWidth: 1,
                    id: d.id + '_line'
                });
            }
        }
    }
    // 删除
    del(id: string) {
        delete this._dataObj[id];
    }
    // 计算节点宽高和位置
    calculate() {
        const id = this._firstId;
        const levelIdMap: Map<number, string[]> = new Map().set(0, [id]); // x轴每层的节点ID
        this._getLevelMapCalculateMaxWidthAddHeightGap(id, levelIdMap, 1);
        this._setPosX(levelIdMap); // 设置位置 x
        this._calculateMaxHeight(levelIdMap);        // 计算高度
        this._setPosY(levelIdMap); // 设置位置 y
        this._subtractGAPRender();
    }
    /**
     * 根据坐标查找ID
     * @param x 
     * @param y 
     * @param padding 距离实际位置的偏移量
     * @returns 
     */
    getIdByXY(x: number, y: number, padding?: number): string | null {
        padding = padding || 0;
        for (const id in this.dataObj) {
            const ele = this.dataObj[id];
            if (ele.x - padding <= x && x <= ele.x + ele.w + padding &&
                ele.y - padding <= y && y <= ele.y + ele.h + padding) {
                return id;
            }
        }
        return null; // 未找到
    }
    // 渲染元素 根据ID
    renderEleById(id: string) {
        const d = this._dataObj[id];
        const ele = $(d.id);
        const textEle = $(d.id + '_text');
        const lineEle = $(d.id + '_line');
        const parentEle = this._dataObj[d.parentId];
        if (ele) {
            ele.setAttribute('height', String(d.h));
            ele.setAttribute('y', String(d.y));
            ele.setAttribute('width', String(d.w));
            ele.setAttribute('x', String(d.x));
        }
        if (textEle) {
            textEle.setAttribute('y', String(d.y + d.h / 2 + 4));
            textEle.setAttribute('x', String(d.x + d.w / 2));
        }
        if (lineEle && parentEle) {
            lineEle.setAttribute('x1', String(parentEle.x + parentEle.w));
            lineEle.setAttribute('y1', String(parentEle.y + parentEle.h / 2));
            lineEle.setAttribute('x2', String(d.x));
            lineEle.setAttribute('y2', String(d.y + d.h / 2));
        }
    }
    // 获取数据对象
    get dataObj(): IDataObj {
        return this._dataObj;
    }
    // 显示悬停元素
    showHoverEles(id: string) {
        if (!id || !this._dataObj[id]) {
            return; // 无效ID
        }
        this._hoverId = id; // 更新悬停ID

        const data = this._dataObj[id];
        const { x, y, w, h } = data;
        const id0 = 'up_hover'; // 上
        let ele0 = $(id0);
        const gPolygonArray0 = [
            { x: x + w / 2 + HOVER_WIDTH / 2, y: y - HOVER_EHGIT - HOVER_WIDTH, },
            { x: x + w / 2 + HOVER_WIDTH + HOVER_WIDTH / 2, y: y - HOVER_WIDTH, },
            { x: x + w / 2 - HOVER_WIDTH / 2, y: y - HOVER_WIDTH, },
        ];
        if (!ele0) {
            const tEle = this._svgBase.gPolygon(gPolygonArray0, {
                fill: 'red',
                id: id0
            }, true);
            ele0 = tEle as unknown as HTMLElement;
            tEle.addEventListener('click', () => {
                this._addNewEle(this._hoverId, 'up');
                this.hideHoverEles();
                this.calculate();
            });
        }
        const id1 = 'right_hover'; // 右
        let ele1 = $(id1);
        const gPolygonArray1 = [
            { x: x + w + HOVER_WIDTH, y: y + h / 2 - HOVER_WIDTH },
            { x: x + w + HOVER_WIDTH + HOVER_EHGIT, y: y + h / 2 },
            { x: x + w + HOVER_WIDTH, y: y + h / 2 + HOVER_WIDTH },
        ];
        if (!ele1) {
            const tEle = this._svgBase.gPolygon(gPolygonArray1, {
                fill: 'black',
                id: id1
            }, true);
            ele1 = tEle as unknown as HTMLElement;
            tEle.addEventListener('click', () => {
                this._addNewEle(this._hoverId, 'right');
                this.hideHoverEles();
                this.calculate();
            });
        }
        const id2 = 'down_hover'; // 下
        let ele2 = $(id2);
        const gPolygonArray2 = [
            { x: x + w / 2 - HOVER_WIDTH / 2, y: y + h + HOVER_WIDTH, },
            { x: x + w / 2 + HOVER_WIDTH + HOVER_WIDTH / 2, y: y + h + HOVER_WIDTH, },
            { x: x + w / 2 + HOVER_WIDTH / 2, y: y + h + HOVER_EHGIT + HOVER_WIDTH, },
        ];
        if (!ele2) {
            const tEle = this._svgBase.gPolygon(gPolygonArray2, {
                fill: 'blue',
                id: id2
            }, true);
            ele2 = tEle as unknown as HTMLElement;
            tEle.addEventListener('click', () => {
                this._addNewEle(this._hoverId, 'down');
                this.hideHoverEles();
                this.calculate();
            });
        }
        const id3 = 'left_hover'; // 左
        let ele3 = $(id3);
        const gPolygonArray3 = [
            { x: x - HOVER_WIDTH, y: y + h / 2 - HOVER_WIDTH, },
            { x: x - HOVER_WIDTH - HOVER_EHGIT, y: y + h / 2, },
            { x: x - HOVER_WIDTH, y: y + h / 2 + HOVER_WIDTH, },
        ];
        if (!ele3) {
            const tEle = this._svgBase.gPolygon(gPolygonArray3, {
                fill: 'green',
                id: id3
            }, true);
            ele3 = tEle as unknown as HTMLElement;
            tEle.addEventListener('click', () => {
                this._addNewEle(this._hoverId, 'left');
                this.hideHoverEles();
                this.calculate();
            });
        }
        const id4 = 'rect_hover'; // 矩形
        let ele4 = $(id4);
        const gRect41 = x - HOVER_WIDTH;
        const gRect42 = y - HOVER_WIDTH;
        const gRect43 = w + HOVER_WIDTH * 2;
        const gRect44 = h + HOVER_WIDTH * 2;
        if (!ele4) {
            const tEle = this._svgBase.gRect(gRect41, gRect42, gRect43, gRect44, {
                stroke: 'red',
                strokeWidth: 1,
                id: id4
            });
            ele4 = tEle as unknown as HTMLElement;
        }

        ele0.style.display = 'block';
        ele0.setAttribute('points', gPolygonArray0.map(p => `${p.x},${p.y}`).join(' '));
        ele1.style.display = 'block';
        ele1.setAttribute('points', gPolygonArray1.map(p => `${p.x},${p.y}`).join(' '));
        ele2.style.display = 'block';
        ele2.setAttribute('points', gPolygonArray2.map(p => `${p.x},${p.y}`).join(' '));
        ele3.style.display = 'block';
        ele3.setAttribute('points', gPolygonArray3.map(p => `${p.x},${p.y}`).join(' '));

        ele4.style.display = 'block';
        ele4.setAttribute('x', String(gRect41));
        ele4.setAttribute('y', String(gRect42));
        ele4.setAttribute('width', String(gRect43));
        ele4.setAttribute('height', String(gRect44));
    }
    // 隐藏悬停元素
    hideHoverEles() {
        const ids = ['up_hover', 'right_hover', 'down_hover', 'left_hover', 'rect_hover'];
        ids.forEach(id => {
            const ele = $(id);
            if (ele) {
                ele.style.display = 'none';
            }
        });
    }


    // 私有内部方法

    // 高度减去间隙
    private _subtractGAPRender() {
        for (const k in this._dataObj) {
            const d = this._dataObj[k];
            d.h -= GAP;
        }
        for (const k in this._dataObj) {
            this.renderEleById(k); // 渲染元素
        }
    }
    // 设置位置Y
    private _setPosY(levelIdMap: Map<number, string[]>) {
        for (let i = 1; i < levelIdMap.size; i++) {
            const levelIds = levelIdMap.get(i);
            if (!levelIds || levelIds.length === 0) {
                continue; // 没有节点
            }
            let startY = 0;
            let parentId = '';
            for (let j = 0; j < levelIds.length; j++) {
                const lId = levelIds[j];
                const { parentId: tParentId } = this._dataObj[lId];
                if (parentId !== tParentId) {
                    parentId = tParentId; // 更新父节点ID
                    const tParentEle = this._dataObj[tParentId];
                    startY = tParentEle.y + tParentEle.h / 2 - tParentEle.children.mh / 2; // 起始y值
                }
                const lEle = this._dataObj[lId];
                const tMaxH = Math.max(lEle.h, lEle.children.mh); // 当前节点的最大高度
                lEle.y = startY + tMaxH / 2 - lEle.h / 2; // 设置节点的y值
                startY += tMaxH; // 更新起始y值
            }
        }
    }
    // 设置位置 X
    private _setPosX(levelIdMap: Map<number, string[]>) {
        // 计算x值
        let maxWX = this._dataObj[this._firstId].x; // 最大宽度位置
        for (let i = 1; i < levelIdMap.size - 1; i++) { // 掐头去尾：第一层为主，最后一层为空
            const levelIds = levelIdMap.get(i);
            const prevIds = levelIdMap.get(i - 1);
            const prevMW = Math.max(...prevIds.map(t => this._dataObj[t].w));
            maxWX += prevMW + GAP;
            levelIds.forEach((lId) => {
                const lEle = this._dataObj[lId];
                lEle.x = maxWX;
            });
        }
    }
    // h 计算最大h值
    private _calculateMaxHeight(levelIdMap: Map<number, string[]>) {
        const len = levelIdMap.size;
        for (let i = len - 2; i >= 0; i--) { // 最后一层为空
            const levelIds = levelIdMap.get(i);
            for (const lId of levelIds) {
                const lEle = this._dataObj[lId];
                if (!lEle.parentId || !this._dataObj[lEle.parentId]) {
                    continue;
                }
                const pEle = this._dataObj[lEle.parentId];
                const children = pEle.children;
                children.mh = children.ids.length > 0 ? children.ids
                    .map(t => Math.max(this._dataObj[t].h, this._dataObj[t].children.mh))
                    .reduce((a, b) => a + b, 0) :
                    0; // 叶子节点的子高度为0
            }
        }
    }
    // w 获取层次，计算最大w值，给高度添加间隙，对应_subtractGAPRender
    private _getLevelMapCalculateMaxWidthAddHeightGap(id: string, levelMap: Map<number, string[]>, level: number) {
        if (!id || !this._dataObj[id]) {
            return;
        }
        const data = this._dataObj[id];
        data.h += GAP; // 每个节点的高度增加间距
        const children = data.children;
        const ids = children.ids.length > 0 ? [...children.ids] : [];
        children.mw = Math.max(...ids.map(t => this._dataObj[id].w), 0); // 叶子节点的子宽度为0
        if (!levelMap.has(level)) {
            levelMap.set(level, ids);
        } else {
            levelMap.get(level).push(...ids);
        }
        level++;
        for (const tId of ids) {
            this._getLevelMapCalculateMaxWidthAddHeightGap(tId, levelMap, level);
        }
    }
    // 添加新节点
    private _addNewEle(id: string, direction: 'up' | 'right' | 'down' | 'left' = 'up') {
        if (!id || !this._dataObj[id]) {
            return; // 无效ID
        }
        const data = this._dataObj[id];
        let { parentId } = data;
        if (direction !== 'right' && (!parentId || !this._dataObj[parentId])) {
            return; // 无效父节点
        }

        const newId = UUID();
        const childrenIds: string[] = [];
        if (direction === 'up') {
            const parentEle = this._dataObj[parentId];
            const { children } = parentEle;
            const index = children.ids.indexOf(id);
            if (index === -1) {
                children.ids.push(newId);
            } else {
                children.ids.splice(index, 0, newId);
            }
        }
        else if (direction === 'down') {
            const parentEle = this._dataObj[parentId];
            const { children } = parentEle;
            const index = children.ids.indexOf(id);
            children.ids.splice(index + 1, 0, newId);
        }
        else if (direction === 'right') {
            const oldChildrenIds = [...data.children.ids];
            const oldEles = oldChildrenIds.map(t => this._dataObj[t]);
            for (const oldEle of oldEles) {
                oldEle.parentId = newId; // 更新旧节点的父节点为新节点
            }
            childrenIds.push(...oldChildrenIds);
            data.children.ids = [newId];
            parentId = id; // 新节点的父节点为当前节点
        }
        else if (direction === 'left') {
            childrenIds.push(id);
            data.parentId = newId; // 当前节点的父节点变为新节点
            const parentEle = this._dataObj[parentId];
            const index = parentEle.children.ids.indexOf(id);
            parentEle.children.ids.splice(index, 1, newId); // 在父节点的子节点中插入新节点
        }

        this.save({
            id: newId,
            x: 0,
            y: 0,
            w: 100,
            h: 50,
            parentId,
            children: {
                ids: childrenIds,
                mh: 0,
                mw: 0
            },
        });
    }

}